package cn.com.yto56.cainiao.exponent.elasticsearch.service.impl;

import cn.com.yto56.basic.framework.core.exception.YtoErrorServerException;
import cn.com.yto56.basic.framework.core.sercurity.MD5;
import cn.com.yto56.basic.framework.core.util.DateUtil;
import cn.com.yto56.basic.framework.core.util.EmptyUtils;
import cn.com.yto56.basic.framework.model.rest.MutiRequest;
import cn.com.yto56.basic.framework.plugin.chain.Executor;
import cn.com.yto56.basic.framework.plugin.chain.config.ExecutorRequest;
import cn.com.yto56.basic.framework.plugin.elasticsearch.ElasticSearchStarter;
import cn.com.yto56.cainiao.exponent.common.ExponentType;
import cn.com.yto56.cainiao.exponent.dto.ExpUploadRequest;
import cn.com.yto56.cainiao.exponent.dto.ExponentRequest;
import cn.com.yto56.cainiao.exponent.elasticsearch.service.CommonService;
import cn.com.yto56.cainiao.exponent.elasticsearch.service.ExponentService;
import cn.com.yto56.cainiao.exponent.elasticsearch.service.FrontHandleService;
import cn.com.yto56.cainiao.exponent.elasticsearch.service.TaskProCenter;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.frameworkset.elasticsearch.client.ClientInterface;
import org.frameworkset.elasticsearch.client.ClientUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;

@Service
@Slf4j
public class ExponentServiceImpl implements ExponentService {


    /**
     * 前置库原始数据.
     */
    public static String INDEX_TYPE = "exponent-origin";
    /**
     * 走件.
     */
    public static String INDEX_TYPE_TMS_TRACE = "exponent-origin";

    public static String INDEX_DATE_PATTEN = "yyyy.MM";
    /**
     * 前置库原始数据.
     */
    private static String INDEX_FORMAT = INDEX_TYPE + "-%s";
    private static final int REQ_COUNT = 16;

    @Autowired
    private ElasticSearchStarter starter;

    @Autowired
    Executor<MutiRequest<ExponentRequest>, ExpUploadRequest> execute;

    @Autowired
    @Qualifier("frontHandleServiceProxyImpl")
    private FrontHandleService frontHandleService;

    @Override
    public void buildOriginIndiceTemp(String templateName) {
        ClientInterface clientUtil = starter.getConfigRestClient("elasticMapper/IndicesMapper.xml");
        //创建模板
        String response = clientUtil.createTempate(templateName.toLowerCase(), templateName);
        String template = clientUtil.executeHttp("/_template/" + templateName.toLowerCase(), ClientUtil.HTTP_GET);
        if (log.isInfoEnabled()) {
            log.info("{}", template);
        }
    }

    /**
     * 样单文件分析
     *
     * @param file
     * @return
     */
    @Override
    public ExecutorRequest<ExpUploadRequest, MutiRequest<ExponentRequest>> executePlugIns(MultipartFile file) {

        //regopm 分析Excel
        InputStream is = null;
        Workbook hssfWorkbook = null;
        try {
            is = file.getInputStream();
            hssfWorkbook = new XSSFWorkbook(is);
        } catch (IOException ex) {
            try {
                is = file.getInputStream();
                hssfWorkbook = new XSSFWorkbook(is);
            } catch (IOException e) {
                e.printStackTrace();
                throw new YtoErrorServerException("读取导入文件失败");
            }
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                    throw new YtoErrorServerException("关闭文件读取流失败");
                }
            }
        }
        if (hssfWorkbook.getNumberOfSheets() <= 0) {
            return new ExecutorRequest<>();
        }
        XSSFSheet sheet = (XSSFSheet) hssfWorkbook.getSheetAt(0);
        List<Map<String, String>> rows = new ArrayList<>();
        if (log.isInfoEnabled()) {
            log.info("读取表格：{}", sheet.getSheetName());
        }
        int rowNumber = 0;
        int i = 0;
        List<String> columnName = new ArrayList<>();
        do {
            columnName.add(sheet.getRow(0).getCell(i).toString());
        } while (++i < sheet.getRow(0).getLastCellNum());
        while (++rowNumber < sheet.getLastRowNum()) {
            int cellNumber = 0;
            Map<String, String> values = new HashMap<>();
            do {
                if (EmptyUtils.isNotEmpty(sheet.getRow(rowNumber)) && EmptyUtils.isNotEmpty(sheet.getRow(rowNumber).getCell(cellNumber))) {
                    values.put(columnName.get(cellNumber), sheet.getRow(rowNumber).getCell(cellNumber).toString());
                }
            } while (++cellNumber < sheet.getRow(cellNumber).getLastCellNum());
            rows.add(values);
        }
        //endregion


        //region 组装插件对象
        String fileName = file.getOriginalFilename();
        String[] fileArgs = fileName.split("#");
        if (fileArgs.length < 2) {
            return new ExecutorRequest<>();
        }
        ExpUploadRequest uploadRequest = new ExpUploadRequest();
        // 缺第三段信息默认 总部
        if (fileArgs.length < 3) {
            uploadRequest.setArea("总部");
        } else {
            uploadRequest.setArea(fileArgs[2]);
        }
        uploadRequest.setDateFmt(DateUtil.toDateString(DateUtil.toDate(fileArgs[1]), "yyyy-MM-dd"));
        uploadRequest.setFileName(fileName);
        uploadRequest.setRowValues(rows);

        MutiRequest<ExponentRequest> items = new MutiRequest<>();
        items.setItems(new ArrayList<>());
        //endregion

        ExecutorRequest<ExpUploadRequest, MutiRequest<ExponentRequest>> original = new ExecutorRequest<>();
        original.setOutputParameter(items)
                .setInitParameter(uploadRequest)
                .setExecuteName(ExponentType.ExecuteName);

        execute.execute(original);

        initCanvassTime(original.getOutputParameter());
         syncOrigin(original.getOutputParameter());
        return original;
    }

    Boolean syncOrigin(MutiRequest<ExponentRequest> items) {
        if (EmptyUtils.isEmpty(items) || EmptyUtils.isEmpty(items.getItems())) {
            return false;
        }
        ClientInterface clientUtil = starter.getRestClient();
        items.getItems().parallelStream().forEach(request -> {
            clientUtil.addDocumentWithId(
                    String.format(INDEX_FORMAT, DateUtil.getFormatedDate(request.getConsumerTime(), INDEX_DATE_PATTEN)),
                    INDEX_TYPE,
                    request,
                    MD5.encryptMD5(String.format("%s-%s-%s", request.getWayBillNo(), request.getExponentType(), request.getExponetMsg()))
            );
        });

        return true;
    }

    private void initCanvassTime(MutiRequest<ExponentRequest> items) {
        List<ExponentRequest> data = items.getItems();
        if (data.size() > 0) {
            if (!ExponentType.TIMELY_CANVASS.getName().equals(data.get(0).getExponentType())) {
                return;
            }
            final BlockingQueue<ExponentRequest> queue = new ArrayBlockingQueue<>(data.size(), false, data);
            CountDownLatch latch = new CountDownLatch(REQ_COUNT);
            TaskProCenter.repeatExecute(REQ_COUNT, () -> {
                ExponentRequest req;
                while ((req = queue.poll()) != null && !Thread.currentThread().isInterrupted()) {
                    try {
                        Date ct = frontHandleService.queryCanvassTime(req.getWayBillNo());
                        if (ct != null) {
                            req.setCanvassTime(ct);
                            req.setDeliveryAndCanvassTimeDiff(Math.abs(CommonService.getDateDiffHour(req.getDeliveryTime(), req.getCanvassTime())));
                        }
                    } catch (Exception e) {
                        log.error("揽收时间查询失败:" + req.getWayBillNo(), e);
                    }
                }
                latch.countDown();
            });
            try {
                latch.await();
            } catch (InterruptedException e) {
                log.error("揽收时间查询等待失败:", e);
            }
        }
    }
}
